package br.com.orion.sga.model.dao;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.faces.FacesException;
import javax.faces.el.EvaluationException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.RollbackException;

import org.apache.log4j.Logger;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.util.JDBCExceptionReporter;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;

import br.com.orion.sga.exception.DaoException;

@Transactional
@Repository
public class GenericDao<T, PK> {

	@PersistenceContext
	protected EntityManager entityManager;
	
	private static Logger logger = Logger.getLogger(ResponsavelDao.class);

	public void save(T entity) throws DaoException {

		try {
			entityManager.persist(entity);
//		} catch (DataAccessException e) {
//			throw new DaoException("Erro ao tentar salvar o registro!");
//		} catch (ConstraintViolationException e2) {
//			throw new DaoException("CPF informado já consta na base de dados!");
		} catch (PersistenceException e3) {
			throw new DaoException("CPF informado já consta na base de dados!");
			//e3.printStackTrace();
		}
//		} catch (TransactionSystemException e4) {
//			throw new DaoException("CPF informado já consta na base de dados!");
//		} catch (FacesException	e5) {
//			throw new DaoException("CPF informado já consta na base de dados!");
//		} catch (TransactionException e6) {
//			throw new DaoException("CPF informado já consta na base de dados!");
//		}
		
	}

	public void update(T entity) throws DaoException {

		try {
			entityManager.merge(entity);
		} catch (DataAccessException e) {
			throw new DaoException("Erro ao tentar atualizar a registro!");
		} catch (ConstraintViolationException e2) {
			throw new DaoException("CPF informado já consta na base de dados!");
		}
	}

	public void delete(T entity) throws DaoException {

		try {
			entityManager.remove(entityManager.merge(entity));
		} catch (DataAccessException e) {
			throw new DaoException("Erro ao tentar excluir o registro! Verifique se há outros registros vinculados a ele.");
		}
	}
	
	@SuppressWarnings("unchecked")
	public T getById(PK id){
		T entity = (T) entityManager.find(getTypeClass(), id);
		return entity;
	}
	
	private Class<?> getTypeClass(){
		Class<?> clazz = (Class <?>) ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		return clazz;
	}
	
	@SuppressWarnings("unchecked")
	public List<T> listAll(){
		Query q = entityManager.createQuery(" from " + getTypeClass().getName());
		return q.getResultList();
	}
	
}
